/* 
 * File:   Sintatico.cpp
 * Author: Pedro-Note
 * 
 * Created on 2 de Novembro de 2010, 13:43
 */

#include "Sintatico.h"

Sintatico::Sintatico() {
}

Sintatico::Sintatico(Arquivo* arq)
{
    this->arq = arq;
}

Sintatico::Sintatico(const Sintatico& orig)
{
    this->arq = orig.arq;
    this->lex = orig.lex;
}

Sintatico::~Sintatico()
{
}

void Sintatico::LerLexema()
{
    this->lex = this->arq->RetornaProximoLexema();
}

void Sintatico::casaLexa(int esperado)
{
    if (this->lex->RetornaToken()!=esperado)
    {
        cout << "Erro linha:" << this->arq->getNumLinha() << " esperado -> " << esperado << " encontrado -> " << *(this->lex);
        throw new exception();
    }
}

void Sintatico::A()
{
    casaLexa(TOKEN_IDENTIFICADOR);
    LerLexema();
    casaLexa(TOKEN_Equal);
    X();
    casaLexa(TOKEN_CommaPoint);
}

void Sintatico::B()
{
    LerLexema();
    casaLexa(TOKEN_Begin);
    LerLexema();

    while(this->lex->RetornaToken()!=TOKEN_END)
    {       
        if((this->lex->RetornaToken() == TOKEN_IDENTIFICADOR ) ||
            (this->lex->RetornaToken() == TOKEN_WHILE ) ||
            (this->lex->RetornaToken() == TOKEN_IF) ||
            (this->lex->RetornaToken() == TOKEN_READ) ||
            (this->lex->RetornaToken() == TOKEN_Write))
        {
             F();
        }
        else
        {
            D();
            LerLexema();
        }
    }

    LerLexema();
    casaLexa(TOKEN_END);
    LerLexema();

}

void Sintatico::C()
{
    while (this->lex->RetornaToken()!=TOKEN_main)
    {
       casaLexa(TOKEN_Final);
       LerLexema();
       casaLexa(TOKEN_IDENTIFICADOR);
       LerLexema();
       casaLexa(TOKEN_Equal);
       LerLexema();
       if(this->lex->RetornaToken()==TOKEN_SUB)
       {
           casaLexa(TOKEN_SUB);
           LerLexema();
       }
       casaLexa(TOKEN_constante);
       LerLexema();
       casaLexa(TOKEN_CommaPoint);
       LerLexema();
    }
}

void Sintatico::D()
{
  LerLexema();
  if (this->lex->RetornaToken() == TOKEN_Final)
      C();
  else
      V();
}

void Sintatico::E()
{
    casaLexa(TOKEN_Write);
    LerLexema();
    casaLexa(TOKEN_9);
    LerLexema();
    if((this->lex->RetornaToken()== TOKEN_9) ||
       (this->lex->RetornaToken() == TOKEN_Final) || 
       (this->lex->RetornaToken() == TOKEN_IDENTIFICADOR) ||
       (this->lex->RetornaToken() == TOKEN_INT) ||
       (this->lex->RetornaToken() == TOKEN_BOOLEAN) ||
       (this->lex->RetornaToken() == TOKEN_BYTE) ||
       (this->lex->RetornaToken() == TOKEN_string))
    {
        X();
        LerLexema();
        while (this->lex->RetornaToken()!= TOKEN_0)
        {
            if(this->lex->RetornaToken()==TOKEN_COMMA)
            {
                casaLexa(TOKEN_COMMA);
                X();
            }
        }
    }
    casaLexa(TOKEN_0);
    LerLexema();
    casaLexa(TOKEN_CommaPoint);
    LerLexema();

}
void Sintatico::F()
{
    switch(this->lex->RetornaToken())
    {
        case TOKEN_IDENTIFICADOR:
            A();
            break;
        case TOKEN_WHILE:
            R();
            break;
        case TOKEN_IF:
            O();
            break;
        case TOKEN_READ:
            L();
            break;
        case TOKEN_Write:
            E();
            break;
        default:
            casaLexa(false);
            break;

    }

}
void Sintatico::I()
{
    LerLexema();
    switch(this->lex->RetornaToken())
    {
        case TOKEN_Plus:
            casaLexa(TOKEN_Plus);
            break;
        case TOKEN_SUB:
            casaLexa(TOKEN_SUB);
            break;
        case TOKEN_Star:
            casaLexa(TOKEN_Star);
            break;
        case TOKEN_Division:
            casaLexa(TOKEN_Division);
            break;
        case TOKEN_CommercialAnd:
             casaLexa(TOKEN_CommercialAnd);
            break;
        case TOKEN_LessOrEqual:
            casaLexa(TOKEN_LessOrEqual);
            break;
        case TOKEN_MoreThanOrEqual:
            casaLexa(TOKEN_MoreThanOrEqual);
            break;
        case TOKEN_exclamation:
            casaLexa(TOKEN_exclamation);
            break;
        case TOKEN_PIPE:
            casaLexa(TOKEN_PIPE);
            break;
        case TOKEN_LessThan:
            casaLexa(TOKEN_LessThan);
            break;
        case TOKEN_BooleanEqual:
            casaLexa(TOKEN_BooleanEqual);
            break;
        case TOKEN_Unlike:
            casaLexa(TOKEN_Unlike);
            break;
        case TOKEN_More:
            casaLexa(TOKEN_More);
            break;
          default:
            casaLexa(false);
            break;
    }
}
void Sintatico::L()
{
    casaLexa(TOKEN_READ);
    LerLexema();
    casaLexa(TOKEN_9);
    LerLexema();
    casaLexa(TOKEN_IDENTIFICADOR);
    LerLexema();
    casaLexa(TOKEN_0);
    LerLexema();
    casaLexa(TOKEN_CommaPoint);
    LerLexema();
}
void Sintatico::N()
{ 
    LerLexema();
    while((this->lex->RetornaToken() == TOKEN_Plus) ||
             (this->lex->RetornaToken() == TOKEN_SUB) ||
             (this->lex->RetornaToken() == TOKEN_Star) ||
             (this->lex->RetornaToken() == TOKEN_Division) ||
            (this->lex->RetornaToken() == TOKEN_CommercialAnd) ||
            (this->lex->RetornaToken() == TOKEN_LessOrEqual) ||
            (this->lex->RetornaToken() == TOKEN_MoreThanOrEqual) ||
            (this->lex->RetornaToken() == TOKEN_exclamation) ||
            (this->lex->RetornaToken() == TOKEN_PIPE) ||
            (this->lex->RetornaToken() == TOKEN_LessThan) ||
            (this->lex->RetornaToken() == TOKEN_BooleanEqual) ||
            (this->lex->RetornaToken() == TOKEN_Unlike) ||
            (this->lex->RetornaToken() == TOKEN_More))
    {
        I();
        X();
    }
}
void Sintatico::O()
{
    casaLexa(TOKEN_IF);
    LerLexema();
    casaLexa(TOKEN_9);
        X();
    LerLexema();
    casaLexa(TOKEN_0);
    LerLexema();
    if(this->lex->RetornaToken() == TOKEN_Final)
        C();
    else
        B();

    P();
}
void Sintatico::P()
{
    LerLexema();
    if(this->lex->RetornaToken() == TOKEN_ELSE)
    {
        casaLexa(TOKEN_ELSE);
        LerLexema();
        if(this->lex->RetornaToken() == TOKEN_Final)
            C();
        else
            B();
    }

}
void Sintatico::R()
{
    casaLexa(TOKEN_WHILE);
    LerLexema();
    casaLexa(TOKEN_9);
    X();
    LerLexema();
    casaLexa(TOKEN_0);
    LerLexema();
    if(this->lex->RetornaToken()!= TOKEN_Begin)
        F();
    else
        B();

}
void Sintatico::S()
{
    //D();
    LerLexema();
    casaLexa(TOKEN_main);
    B();
    casaLexa(TOKEN_Point);


}
void Sintatico::T()
{
    switch(this->lex->RetornaToken())
    {
        case TOKEN_INT:
            casaLexa(TOKEN_INT);
            break;
        case TOKEN_BOOLEAN:
            casaLexa(TOKEN_BOOLEAN);
            break;
        case TOKEN_BYTE:
            casaLexa(TOKEN_BYTE);
            break;
        case TOKEN_string:
            casaLexa(TOKEN_string);
            break;
        default:
            casaLexa(false);
            break;
    }

}

void Sintatico::V()
{    
    if(this->lex->RetornaToken() == TOKEN_IDENTIFICADOR)
    {
         casaLexa(TOKEN_IDENTIFICADOR);
         LerLexema();
         casaLexa(TOKEN_Equal);
         LerLexema();
         if(this->lex->RetornaToken()==TOKEN_SUB)
         {
           casaLexa(TOKEN_SUB);
           LerLexema();
         }
       casaLexa(TOKEN_constante);
       LerLexema();
      
    }
    else
    {
        T();
        LerLexema();
        casaLexa(TOKEN_IDENTIFICADOR);
        LerLexema();
        while(this->lex->RetornaToken()==TOKEN_COMMA)
        {
            casaLexa(TOKEN_COMMA);
            LerLexema();
            casaLexa(TOKEN_IDENTIFICADOR);
            LerLexema();

        }
     }
    casaLexa(TOKEN_CommaPoint);
    LerLexema();
}

void Sintatico::X()
{
     LerLexema();
     if(this->lex->RetornaToken()== TOKEN_9)
     {
         casaLexa(TOKEN_9);
         LerLexema();
        if(this->lex->RetornaToken()== TOKEN_exclamation)
        {
            casaLexa(TOKEN_exclamation);

        }
         LerLexema();
         if (this->lex->RetornaToken()== TOKEN_IDENTIFICADOR)
            casaLexa(TOKEN_IDENTIFICADOR);
         else
             casaLexa(TOKEN_constante);
         
         N();
         casaLexa(TOKEN_0);

     }
     else
     {
         if (this->lex->RetornaToken()== TOKEN_IDENTIFICADOR)
            casaLexa(TOKEN_IDENTIFICADOR);
         else
             casaLexa(TOKEN_constante);
        
         N();
     }


}
